package cronservice

import (
	"errors"
	"fmt"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gcron"
	"github.com/gogf/gf/os/glog"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"
	"go-middle/app/common/model/cron"
	"go-middle/app/common/model/cron_log"
	"go-middle/app/common/model/server_has_model"
)

//GetConTabLog 任务日志列表
func GetConTabLog(param cron_log.SelectPageReq) (total int, out []*cron_log.Entity) {
	model := cron_log.Model
	if param.Search != "" {
		v := "%" + param.Search + "%"
		model = model.Where("cron_name like ?", v)
	}
	if param.Status != "" {
		model = model.Where("status = ?", param.Status)
	}
	if param.Protocol != "" {
		model = model.Where("protocol = ?", param.Protocol)
	}
	if param.ServerId != "" {
		model = model.Where("server_id = ?", param.ServerId)
	}
	total, err := model.Count()
	if err != nil {
		glog.Error(err)
		return
	}
	out, err = model.FieldsEx("result").
		Page(param.Page, param.Limit).
		Order("id desc").
		All()
	if err != nil {
		glog.Error(err)
		return
	}
	return
}

//GetConTab 任务列表
func GetConTab(param cron.SelectPageReq) (total int, out []*cron.Entity) {
	model := cron.Model
	if param.Search != "" {
		v := "%" + param.Search + "%"
		model = model.Where("name like ?", v)
	}
	if param.Status != "" {
		model = model.Where("status = ?", param.Status)
	}
	if param.Protocol != "" {
		model = model.Where("protocol = ?", param.Protocol)
	}
	if param.ServerId != "" {
		model = model.As("a").InnerJoin(server_has_model.Table+" b", fmt.Sprintf("a.id=b.model_id and b.model='%s'", cron.Table))
	}
	total, err := model.Count()
	if err != nil {
		glog.Error(err)
		return
	}
	out, err = model.
		Page(param.Page, param.Limit).
		Order("id desc").
		All()
	if err != nil {
		glog.Error(err)
		return
	}
	return
}

//SaveCron 保存任务
func SaveCron(info interface{}) error {
	add, ok1 := (info).(cron.ReqAdd)
	edit, ok2 := (info).(cron.ReqEdit)
	if !ok1 && !ok2 {
		return errors.New("参数类型错误")
	}
	if ok2 {
		mode, _ := cron.FindOne("id=?", edit.Id)
		cnt, _ := cron.Model.Where("name=? and name <> ?", edit.Name, mode.Name).Count()
		if cnt > 0 {
			return errors.New("任务名重复")
		}
		//编辑
		mode.IsSingleton = edit.IsSingleton
		mode.Name = edit.Name
		mode.Pattern = edit.Pattern
		mode.Protocol = edit.Protocol
		mode.Command = edit.Command
		mode.Method = edit.Method
		mode.Status = edit.Status
		mode.Timeout = edit.Timeout
		mode.RetryCount = edit.RetryCount
		mode.RetryInterval = edit.RetryInterval
		mode.Remark = edit.Remark
		mode.UpdateTime = gtime.Now().Unix()
		_, err := mode.Update()
		if err != nil {
			return err
		}
		//更新调度服务
		deleteTask(edit.Id)
		if mode.Status == 1 {
			//添加调度服务
			err = addTask(*mode)
			if err != nil {
				return err
			}
		}
	} else {
		cnt, _ := cron.Model.Where("name=?", add.Name).Count()
		if cnt > 0 {
			return errors.New("任务名重复")
		}
		var mode cron.Entity
		//新增
		mode.IsSingleton = add.IsSingleton
		mode.Name = add.Name
		mode.Pattern = add.Pattern
		mode.Protocol = add.Protocol
		mode.Command = add.Command
		mode.Method = add.Method
		mode.Status = add.Status
		mode.Timeout = add.Timeout
		mode.RetryCount = add.RetryCount
		mode.RetryInterval = add.RetryInterval
		mode.Remark = add.Remark
		mode.CreateTime = gtime.Now().Unix()
		mode.UpdateTime = gtime.Now().Unix()
		_, err := mode.Insert()
		if err != nil {
			return err
		}
		if mode.Status == 1 {
			//添加调度服务
			err = addTask(mode)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

//DeleteCron 删除任务
func DeleteCron(ids []int64) error {
	tx, err := g.DB().Begin()
	if err == nil {
		_, err = cron.Model.TX(tx).Where("id in (?)", ids).Delete()
		if err != nil {
			glog.Error(err)
			_ = tx.Rollback()
			return err
		}
		_, err = server_has_model.Model.Where("model_id in (?) and model=?", ids, cron.Table).Delete()
		if err != nil {
			glog.Error(err)
			_ = tx.Rollback()
			return err
		}
		err = tx.Commit()
		if err != nil {
			return err
		}
	}
	for _, v := range ids {
		deleteTask(v)
	}
	return err
}

//GetCronByID 根据ID获取任务
func GetCronByID(id int64) *cron.Entity {
	res, _ := cron.Model.FindOne("id=?", id)
	return res
}

//GetCronLogByID 根据ID获取日志
func GetCronLogByID(id int64) *cron_log.Entity {
	res, _ := cron_log.Model.FindOne("id=?", id)
	return res
}

//Restart 重启任务
func Restart() {
	glog.Info("开始初始化定时任务")
	taskNum := 0
	page := 1
	pageSize := 1000
	maxPage := 1000
	for page < maxPage {
		taskList, err := cron.Model.Where("status=1").Page(page, pageSize).All()
		if err != nil {
			glog.Fatalf("定时任务初始化#获取任务列表错误: %s", err)
		}
		if len(taskList) == 0 {
			break
		}
		for _, item := range taskList {
			err = addTask(*item)
			if err != nil {
				glog.Error("添加任务到调度器失败#", err)
			}
			taskNum++
		}
		page++
	}
	glog.Infof("定时任务初始化完成, 共%d个定时任务添加到调度器", taskNum)
}

//添加调度任务
func addTask(item cron.Entity) (err error) {
	taskModel := new(cron.Task)
	taskModel.Entity = item
	taskFunc := createJob(*taskModel)
	if taskFunc == nil {
		err = fmt.Errorf("创建任务处理Job失败,不支持的任务协议#", taskModel.Protocol)
		return
	}
	cronName := gconv.String(taskModel.Id)
	if taskModel.IsSingleton == 1 {
		_, err = gcron.AddSingleton(taskModel.Pattern, taskFunc, cronName)
	} else {
		_, err = gcron.Add(taskModel.Pattern, taskFunc, cronName)
	}
	return
}

//删除调度任务
func deleteTask(id int64) {
	job := gcron.Search(gconv.String(id))
	if job != nil {
		job.Close()
	}
}

// 添加单次任务到调度器
func RunTask(item cron.Entity) (err error) {
	taskModel := new(cron.Task)
	taskModel.Entity = item
	taskFunc := createJob(*taskModel)
	if taskFunc == nil {
		err = fmt.Errorf("创建任务处理Job失败,不支持的任务协议#", taskModel.Protocol)
		return
	}
	cronName := gconv.String(taskModel.Id) + gtime.Now().TimestampMicroStr()
	_, err = gcron.AddOnce("* * * * * *", taskFunc, cronName)
	return
}
